﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Web.Security;
using Peak.Core;
using Peak.Core.DataInterfaces;
using System.Web;
using Peak.Web.Controllers.Providers;

namespace Peak.Web.Controllers.Services
{
  public class MembershipService : IMembershipService
  {
    private readonly IUserRepository _userRepository;
    private readonly MembershipProvider _provider;

    public MembershipService(IUserRepository userRepository)
      : this(null,userRepository)
    {      
    }

    public MembershipService(MembershipProvider provider,IUserRepository userRepository)
    {
      _provider = provider ?? Membership.Provider;
      _userRepository = userRepository;
    }

    public int MinPasswordLength
    {
      get
      {
        return _provider.MinRequiredPasswordLength;
      }
    }

    public bool ValidateUser(string userName, string password)
    {
      if (String.IsNullOrEmpty(userName)) 
        throw new ArgumentException("Value cannot be null or empty.", "userName");
      if (String.IsNullOrEmpty(password)) 
        throw new ArgumentException("Value cannot be null or empty.", "password");
      
      User usr = _userRepository.GetByUserName(userName);
      if (usr == null || usr.IsLockedOut)
        return false;

      if (usr.Password == EncodePassword(password))
      {
        usr.LastLoginDate = DateTime.Now;
        return true;        
      }
      else
      {
        return false;
      }
    }
    
    private string EncodePassword(string password)
    {
      HMACSHA1 hash = new HMACSHA1();
      hash.Key = new byte[]{23,34,54,32,23,1,1};
      return Convert.ToBase64String(hash.ComputeHash(Encoding.Unicode.GetBytes(password)));      
    }

    public CreateUserStatus CreateUser(string userName, string password, string email)
    {
      if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
      if (String.IsNullOrEmpty(password)) throw new ArgumentException("Value cannot be null or empty.", "password");
      if (String.IsNullOrEmpty(email)) throw new ArgumentException("Value cannot be null or empty.", "email");

      if (_userRepository.GetByUserName(userName) != null)
        return CreateUserStatus.DuplicateUserName;

      if (_userRepository.GetByEmail(email) != null)
        return CreateUserStatus.DuplicateEmail;

      User user = new User();
      user.UserName = userName;
      user.Password = EncodePassword(password);
      user.Email = email;

      _userRepository.SaveOrUpdate(user);
      return CreateUserStatus.Success;
    }

    public bool ChangePassword(string userName, string oldPassword, string newPassword)
    {
      if (String.IsNullOrEmpty(userName)) throw new ArgumentException("Value cannot be null or empty.", "userName");
      if (String.IsNullOrEmpty(oldPassword)) throw new ArgumentException("Value cannot be null or empty.", "oldPassword");
      if (String.IsNullOrEmpty(newPassword)) throw new ArgumentException("Value cannot be null or empty.", "newPassword");

      // The underlying ChangePassword() will throw an exception rather
      // than return false in certain failure scenarios.
      try
      {
        MembershipUser currentUser = _provider.GetUser(userName, true /* userIsOnline */);
        return currentUser.ChangePassword(oldPassword, newPassword);
      }
      catch (ArgumentException)
      {
        return false;
      }
      catch (MembershipPasswordException)
      {
        return false;
      }
    }   

    public User User
    {
      get
      {
        return _userRepository.GetByUserName(HttpContext.Current.User.Identity.Name);
      }      
    }        
  }
}